package com.squirrel.michale;/*
* Copyright (c) Huawei Technologies Co., Ltd. 2021-2023. All rights reserved.
* Description: 上机编程认证
* Note: 缺省代码仅供参考，可自行决定使用、修改或删除
*/

import java.util.Map;
import java.util.List;
import java.util.Stack;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.nio.charset.StandardCharsets;

import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import java.util.regex.Pattern;
import java.util.regex.Matcher;

import java.lang.reflect.InvocationTargetException;

// 以下为考题输入输出框架，此部分代码不建议改动；提交代码时请勿包含下面代码
public class Main {
    public static void main(String[] args) throws IOException {
        try (InputReaderPlus reader = new InputReaderPlus(new BufferedInputStream(System.in))) {
            var count = reader.readSingle(Number.class).intValue();
            var strings = reader.readList(String.class);

            var result = new Solution().commonChars(count, strings);
            System.out.println(ToJSONOutput.toJSONString(char[].class, result));
        }
    }
}

class ClazzExec<T> {
    private Class<T> clazz;
    private MethodParasMapping parasMapping;

    @SuppressWarnings(value = {"unchecked"})
    ClazzExec(String className) {
        try {
            String pkgName = ClazzExec.class.getPackageName();
            String fullClassName = pkgName.length() > 0 ? (pkgName + "." + className) : className;
            this.clazz = (Class<T>) Class.forName(fullClassName);
        } catch (Exception ex) {
            System.out.println("Class'name error ! detail: " + ex);
        }
        this.parasMapping = new MethodParasMapping();
    }

    void execMethods(Map<String, MethodDesc> methodDescs, List<MethodData> methodDatas) {
        if (methodDescs == null || methodDatas == null) {
            System.out.println("classDescs or datas is null!");
            return;
        }
        try {
            // 假设构造函数唯一（参数序列相同）
            var first = methodDatas.remove(0);
            var desc = methodDescs.get(first.name);
            if (desc == null) {
                System.out.println("input format error!");
                return;
            }

            Object[] initArgs = parasMapping.mappingParasData(first.parasData, desc);
            T instance = clazz.getDeclaredConstructor(desc.paraTypes)
                .newInstance(initArgs);
            if (desc.returnType != null) { // 设计题才需要打印
                System.out.println("null");
            }

            // 执行除构造函数以外的各函数，非设计题执行一次
            for (var methodData : methodDatas) {
                desc = methodDescs.get(methodData.name);
                if (desc == null) {
                    System.out.println("input format error!");
                    continue;
                }

                var res = clazz.getDeclaredMethod(desc.name, desc.paraTypes)
                    .invoke(instance, parasMapping.mappingParasData(methodData.parasData, desc));

                // 后续待用 fastjson（JSON.toJSONString(...)）进行替代或简化
                System.out.println(ToJSONOutput.toJSONString(desc.returnType, res));
            }
        } catch (SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException ex) {
            ex.printStackTrace();
        } catch (InvocationTargetException ex) {
            ex.printStackTrace();
            System.out.println("函数执行异常: " + ex.getCause().getMessage());
        }catch (Exception ex) {
            System.out.println("函数执行中的其他异常： " + ex.toString());
        }
    }

    // 自定义类型注册 Function<List<?>, ? extends R> intoSDO
    <R> void regTypeMapping(Class<R> key, Function<Object, Object> intoFunc) {
        this.parasMapping.regTypeMapping(key, intoFunc);
    }

    static private class MethodParasMapping {
        private Map<Class<?>, Function<Object, Object>> typeMappings;

        MethodParasMapping() {
            this.typeMappings = new HashMap<>();
            init();
        }

        @SuppressWarnings(value = {"unchecked"})
        private void init() {
            // 转换：String -> char，不必要校验class
            this.typeMappings.put(char.class, (val) -> {
                return ((String) val).charAt(0);
            });

            // 转换：List<String> -> char[]（每个成员都是单字符），另，String -> char[]自行处理
            this.typeMappings.put(char[].class, (val) -> {
                return String.join("", (List<String>) val).toCharArray();
            });

            // 转换：List<List<String>> -> char[][]（每个成员都是单字符），另，或 List<String> -> char[][]自行处理
            this.typeMappings.put(char[][].class, (val) -> {
                var list = (List<List<String>>) val;
                var charArr2Dim = new char[list.size()][];
                for (int i = 0; i < list.size(); i++) {
                    charArr2Dim[i] = String.join("", list.get(i)).toCharArray();

                }
                return charArr2Dim;
            });

            // 转换：boolean, boolean[]，暂不提供char[][]
            this.typeMappings.put(boolean.class, (val) -> {
                return ((Boolean) val).booleanValue();
            });
            this.typeMappings.put(boolean[].class, (val) -> {
                var list = (List<Boolean>) val;
                var boolArr = new boolean[list.size()];
                for (int i = 0; i < list.size(); i++) {
                    boolArr[i] = list.get(i).booleanValue();
                }
                return boolArr;
            });

            // 转换：int, int[]，int[][]
            this.typeMappings.put(int.class, (val) -> {
                return ((Number) val).intValue();
            });
            this.typeMappings.put(int[].class, (val) -> {
                return ((List<Number>) val).stream()
                    .mapToInt(Number::intValue).toArray();
            });
            this.typeMappings.put(int[][].class, (val) -> {
                return ((List<List<Number>>) val).stream()
                    .map(list -> {
                        return list.stream().mapToInt(Number::intValue).toArray();
                    }).toArray(int[][]::new);
            });

            // 转换：long, long[]，long[][]
            this.typeMappings.put(long.class, (val) -> {
                return ((Number) val).longValue();
            });
            this.typeMappings.put(long[].class, (val) -> {
                return ((List<Number>) val).stream()
                    .mapToLong(Number::longValue).toArray();
            });
            this.typeMappings.put(long[][].class, (val) -> {
                return ((List<List<Number>>) val).stream()
                    .map(list -> {
                        return list.stream().mapToLong(Number::longValue).toArray();
                    }).toArray(long[][]::new);
            });

            // 另，暂不提供 double，double[], double[][] 更不常用
        }

        // 自定义类型注册 Function<List<?>, ? extends R> intoSDO
        <R> void regTypeMapping(Class<R> key, Function<Object, Object> intoFunc) {
            this.typeMappings.put(key, intoFunc);
        }

        Object[] mappingParasData(List<?> parasData, MethodDesc methodDesc) {
            // 容错，paraTypes.length != paraTypesEx.length 已经检查过
            if (parasData == null || parasData.size() != methodDesc.paraTypes.length) {
                return new Object[]{};
            }

            Object[] res = new Object[parasData.size()];
            for (int i = 0; i < parasData.size(); i++) {
                var obj = parasData.get(i);
                var mapping = this.typeMappings.get(methodDesc.paraTypes[i]);
                if (mapping != null) { // 一般为基本类型转换（char, boolean, int, long, double，及其数组（含二维）
                    res[i] = mapping.apply(obj);
                } else if (methodDesc.paraTypes[i].equals(List.class)) { // List处理，嵌套或自定义
                    if (methodDesc.paraTypesEx == null || methodDesc.paraTypesEx[i] == null) { // 如果List成员是对象类型（且为JSON格式之一），不需要处理
                        res[i] = obj;
                    } else { // 自定义类型
                        var list = (List<?>) obj;
                        final Function<Object, Object> mapping2 = this.typeMappings.get(methodDesc.paraTypesEx[i]);
                        res[i] = list.stream().map(el -> mapping2.apply(el)).collect(Collectors.toList());
                    }
                } else { // 异常分支，先行直接赋值
                    res[i] = obj;
                }
            }

            return res;
        }
    }

}

// 注：java17 可使用 record ClassDisc(...){} 定义
class MethodDesc {
    String name; // 函数定义的实际名称，和输入的可能不同（格式不同导致）
    Class<?> returnType;
    Class<?>[] paraTypes; // 目标转换类型，可以是空数组[]（不要为 null），
    Class<?>[] paraTypesEx; // 可选，List中嵌套类型或其他特殊处理，paraTypes.length == paraTypesEx.length
    MethodDesc(String name, Class<?> returnType, Class<?>[] paraTypes) {
        this.name = name;
        this.returnType = returnType;
        this.paraTypes = paraTypes;
        if (paraTypes == null) {
            System.out.println("paras define error，paraTypes is null");
            this.paraTypes = new Class<?>[0];
        }
    }
    MethodDesc(String name, Class<?> returnType, Class<?>[] paraTypes, Class<?>[] paraTypesEx) {
        this(name, returnType, paraTypes);
        if (paraTypesEx == null || paraTypes.length != paraTypesEx.length) {
            System.out.println("paras define error， paraTypes.length != paraTypesEx.length");
            return;
        }
        this.paraTypesEx = paraTypesEx;
    }
}

// 形如： delete(true, "35", [1, 2, 3])，含构造函数
class MethodData {
    String name = null; // 输入读出的名称
    List<?> parasData = null;
    MethodData() {}
    MethodData(String name, List<?> parasData) {
        this.name = name;
        this.parasData = parasData;
    }
    public String toString() {
        return String.format(java.util.Locale.ROOT, "%s = %s",
            this.name, this.parasData);
    }
}

// 原则：基本类型用数组（如：int[]，long[][]，boolean[]），对象类型用List（如：List<String>, List<DIYObject>）
class InputReaderPlus implements AutoCloseable {
    private CharReader charReader;
    private Parser parser;

    InputReaderPlus(BufferedInputStream bis) {
        try {
            this.charReader = new CharReader(bis);
            // 或者 "ThirdParser", MyParser
            final String pkgName = InputReaderPlus.class.getPackageName();
            final String classRawName = "ThirdParser";
            String className = pkgName.length() > 0 ? pkgName + "." + classRawName : classRawName;
            parser = (Parser) Class.forName(className).getDeclaredConstructor().newInstance();
        } catch (Exception ex) {
            System.out.println(ex);
        }
    }

    @SuppressWarnings("unchecked")
    private <T> T checkExpectedType(Object obj, Class<T> clazz) {
        if (clazz.isInstance(obj)) {
            return (T) obj;
        }
        throw new ClassCastException("Cannot case parsed result from: "
            + obj.getClass().getName() + " to expected type: " + clazz.getName());
    }

    // 当前仅支持：Number, String, Boolean，基本类型自己转换使用。如：.readSingle(Number.class).intValue()
    <T> T readSingle(Class<T> clazz) throws IOException {
        List<T> tempList = this.parser.parseArray("[" + this.charReader.nextSingle() + "]", clazz);
        return tempList.get(0);
    }

    // 数组转换如 .readList(Number.class).stream().mapToInt(Number::intValue).toArray();
    <T> List<T> readList(Class<T> clazz) throws IOException {
        return this.parser.parseArray(this.charReader.nextList(), clazz);
    }

    <R> R readSingle(Function<Object, ? extends R> intoSDO) throws IOException {
        return intoSDO.apply(this.readObjList(this.charReader.nextList()));
    }

    // List2Dim of Object，同构对象类型（如：String等），并是确定类型。另，基本类型优先使用形如 int[][], long[][]等
    <T> List<List<T>> readList2Dim(Class<T> clazz) throws IOException {
        return this.readObjList(this.charReader.nextList()).stream()
            .map(el -> {
                return ((List<?>) el).stream()
                    .map(val -> checkExpectedType(val, clazz)).collect(Collectors.toList());
            }).collect(Collectors.toList());
    }

    <T> List<List<T>> readList2Dim(Function<Object, T> intoSDO) throws IOException {
        return this.readObjList(this.charReader.nextList()).stream()
            .map(el -> {
                return ((List<?>) el).stream()
                    .map(val -> intoSDO.apply(val)).collect(Collectors.toList());
            }).collect(Collectors.toList());
    }

   // List of Array，同构的基本类型数组（形如：int[], long[])，再使用 .readMatrix(...).toArray(IntFunction<A> generator)）转换
    <T> List<T> readMatrix(Function<Object, ? extends T> intoSDO) throws IOException {
        return this.readObjList(this.charReader.nextList()).stream()
            .map(el -> {
                return intoSDO.apply(el);
            }).collect(Collectors.toList());
    }

    /**
     *  转换成具体Matrix时，如：int[][]转换参考如下代码：
     *  var matrix = reader.readMatrix((val) -> {
     *      return ((List<?>) val).stream().mapToInt(el -> ((Number) el).intValue()).toArray();
     *  }).toArray(int[][]::new);
     */

    // List of SDO(self-defining object，异构对象类型），使用如： .readList(DIYClass::parseDIYClass)
    <R> List<R> readList(Function<Object, ? extends R> intoSDO) throws IOException {
        return this.readMatrix(intoSDO);
    }

    /**
     * 自定义类型的定义和使用参考如下：
     * private static class DIYClass {
     *     int id;
     *     String name;
     *     static DIYClass parseDIYClass(Object data) {
     *         DIYClass val = new DIYClass();
     *         List<?> arr = (List<?>) data;
     *         val.id = ((Number) arr.get(0)).intValue();
     *         val.name = (String) arr.get(1);
     *         return val;
     *     }
     *     public String toString() {
     *         return String.format(Locale.ROOT, "[%d, \"%s\"]", this.id, this.name);
     *     }
     * }
     */

    // 函数读取和校验，形如： delete(true, "35", [1, 2, 3])
    static private Pattern pattern = Pattern.compile("^(\\w+)\\((.*)\\)$");

    // List of 方法数据（MethodData）
    List<MethodData> readMethodDatas(List<String> datas) throws IOException {
        return datas.stream().map(el -> { // 编码格式 StandardCharsets.UTF_8
                    MethodData funcApi = new MethodData();
                    Matcher matcher = pattern.matcher(el.trim());
                    if (matcher.find()) {
                        funcApi.name = matcher.group(1);
                        String paraStr = matcher.group(2);
                        if (paraStr != null && paraStr.length() > 0) {
                            try {
                                funcApi.parasData = this.readObjList("[" + paraStr + "]");
                            } catch (Exception ex) {
                                System.out.println(ex);
                            }
                        }
                    } else {
                        System.out.println("function format error! " + el.trim());
                    }

                    return funcApi;
                }).collect(Collectors.toList());
    }

    List<MethodData> readMethodDatas() throws IOException {
        return readMethodDatas(this.charReader.getAllBytes().lines().collect(Collectors.toList()));
    }

    // 万能使用。一般用不到，如果需要再改成 protected
    private List<Object> readObjList(String data) throws IOException {
        return this.parser.parseArray(data);
    }

    // 自动释放资源 try-resource
    public void close() throws IOException {
        this.charReader.close();
    }

    static private class CharReader {
        private static char EOF_CTRL_Z = 26;
        private static char EOF_CTRL_D = 4;
        private BufferedReader br;
        private StringBuilder strBuff; // 可以改成缓存方式读取，每次不超过 1024
        private int pos;
        CharReader(BufferedInputStream bis) {
            this.br = new BufferedReader(new InputStreamReader(bis, StandardCharsets.UTF_8));
            init();
            this.pos = 0;
        }

        private void init() {
            try {
                String temp;
                this.strBuff = new StringBuilder(1000);
                while ((temp = br.readLine()) != null && temp.length() != 0) {
                    strBuff.append(temp);
                    strBuff.append('\n');
                    if (temp.length() > 0 && isEOF(temp.charAt(temp.length() - 1))) {
                        break;
                    }
                }
            } catch (Exception ex) {
                System.out.println(ex);
            }
        }

        // 应该是：数字（含负数），字符串（可支持[\"\/\\]等少量特殊符号），true/false的其中一种
        String nextSingle() {
            skipSpaceChar();
            if (!isSingleStart()) {
                System.out.println("Invalid format, A Single text must start with [0-9-tf\"]. ");
                return "";
            }
            StringBuilder ssb = new StringBuilder(128);
            while (pos < strBuff.length() && !(strBuff.charAt(pos) == '\n' || isEOF(strBuff.charAt(pos)))) {
                ssb.append(strBuff.charAt(pos++));
            }

            return ssb.toString();
        }

        private boolean isSingleStart() {
            char ch = '\n';
            if (pos < strBuff.length()) {
                ch = strBuff.charAt(pos);
            }
            var isDigit = (Character.isDigit(ch) || ch == '-');
            var isBool = (ch == 't' || ch == 'f');
            return (ch == '\"' || isDigit || isBool);
        }

        String nextList() {
            skipSpaceChar();
            if (!isListStart()) {
                System.out.println("Invalid format, Array/List text must start with '['");
                return "[]";
            }
            StringBuilder ssb = new StringBuilder(512);
            Stack<Character> flag = new Stack<>();
            ssb.append((char) strBuff.charAt(pos));
            flag.push((char) strBuff.charAt(pos++));
            int strFlag = 0;
            while (pos < strBuff.length() && flag.size() > 0) {
                if (strBuff.charAt(pos) == (byte) '\"' && ssb.charAt(ssb.length() - 1) != '\\') { // 引号不会是首个字符
                    strFlag++;
                    strFlag %= 2;
                }
                if (strBuff.charAt(pos) == (byte) '[' && strFlag == 0) {
                    flag.push((char) strBuff.charAt(pos));
                } else if (strBuff.charAt(pos) == (byte) ']' && strFlag == 0) {
                    flag.pop();
                }
                ssb.append((char) strBuff.charAt(pos++));
            }
            return ssb.toString();
        }

        private boolean isListStart() {
            return (pos < strBuff.length() && strBuff.charAt(pos) == '[');
        }

        private boolean isEOF(char ch) {
            return ch == EOF_CTRL_Z || ch == EOF_CTRL_D;
        }

        private void skipSpaceChar() {
            while (pos < strBuff.length() && Character.isWhitespace(strBuff.charAt(pos))) {
                pos++;
            }
        }

        String getAllBytes() {
            skipSpaceChar();
            return this.strBuff.substring(this.pos);
        }

        void close() throws IOException {
            this.br.close();
        }
    }
}

// json解析接口，使用自研或三方（fastjson），计划24年7月1日变更框架：自研 --> 三方
interface Parser  {
    List<Object> parseArray(String data) throws IOException;

    <T> List<T> parseArray(String data, Class<T> clazz) throws IOException;
}

class ThirdParser implements Parser {
    public List<Object> parseArray(String data) throws IOException {
        return com.alibaba.fastjson.JSON.parseArray(data);
    }
    public <T> List<T> parseArray(String data, Class<T> clazz) throws IOException {
        return com.alibaba.fastjson.JSON.parseArray(data, clazz);
    }
}

class ToJSONOutput {
    private static final int FEATHER_NUM = 2;
    private final String[] defaultFeathers = new String[]{", ", ", "};

    private final String[] feathers = new String[FEATHER_NUM];
    private Map<Class<?>, Function<Object, String>> toJsonMappings;
    private static ToJSONOutput instance;
    private ToJSONOutput(String[] feathers2) {
        IntStream.range(0, FEATHER_NUM)
            .forEach(idx -> {
                this.feathers[idx] = (idx < feathers2.length) ? feathers2[idx] : defaultFeathers[idx];
            });

        this.toJsonMappings = new HashMap<>();
        init();
    }
    static private ToJSONOutput instances(String[] feathers2) {
        if (instance == null) {
            instance = new ToJSONOutput(feathers2);
        } else {
            IntStream.range(0, FEATHER_NUM)
                .forEach(idx -> {
                    instance.feathers[idx] = (idx < feathers2.length) ? feathers2[idx] : instance.defaultFeathers[idx];
                });
        }
        return instance;
    }

    private void init() {
        // 不常用的缺省不提供，主要如：char, boolean[]

        this.toJsonMappings.put(void.class, (val) -> {
            return "null";
        });

        this.toJsonMappings.put(boolean.class, (val) -> {
            return (boolean) val ? "true" : "false";
        });
        this.toJsonMappings.put(boolean[].class, (boolArr) -> {
            boolean[] arr = (boolean[]) boolArr;
            return IntStream.range(0, arr.length).mapToObj(idx -> {
                return arr[idx] ? "true" : "false";
            }).collect(Collectors.joining(", ", "[", "]"));
        });

        this.toJsonMappings.put(int.class, (val) -> {
            return String.valueOf(val);
        });
        this.toJsonMappings.put(int[].class, (intArr) -> {
            return Arrays.stream((int[]) intArr)
                .mapToObj(String::valueOf)
                .collect(Collectors.joining(instance.feathers[0], "[", "]"));
        });
        this.toJsonMappings.put(int[][].class, (intMatrix) -> {
            return Arrays.stream((int[][]) intMatrix)
                .map(arr -> {
                    return Arrays.stream(arr)
                        .mapToObj(String::valueOf)
                        .collect(Collectors.joining(instance.feathers[1], "[", "]"));
                }).collect(Collectors.joining(instance.feathers[0], "[", "]"));
        });

        this.toJsonMappings.put(long.class, (val) -> {
            return String.valueOf(val);
        });
        this.toJsonMappings.put(long[].class, (intArr) -> {
            return Arrays.stream((long[]) intArr)
                .mapToObj(String::valueOf)
                .collect(Collectors.joining(instance.feathers[0], "[", "]"));
        });
        this.toJsonMappings.put(long[][].class, (longMatrix) -> {
            return Arrays.stream((long[][]) longMatrix)
                .map(arr -> {
                    return Arrays.stream(arr)
                        .mapToObj(String::valueOf)
                        .collect(Collectors.joining(instance.feathers[1], "[", "]"));
                }).collect(Collectors.joining(instance.feathers[0], "[", "]"));
        });

        this.toJsonMappings.put(String.class, (val) -> {
            return "\"" + val + "\"";
        });

        // 字符串，以及自定义类型等
        this.toJsonMappings.put(List.class, (list) -> {
            return list2String((List<?>) list, 0);
        });

        this.toJsonMappings.put(char[].class, (val) -> {
            var localVal = (char[]) val;
            if (localVal.length == 0) {
                return "[]";
            }
            return list2String(Stream.of(String.valueOf(localVal).split("")).collect(Collectors.toList()), 0);
        });
    }

    // 关键解决嵌套的场景
    private String list2String(List<?> elements, int cycle) {
        if (cycle >= FEATHER_NUM) {
            cycle = Math.min(cycle, FEATHER_NUM - 1);
        }

        StringBuilder buff = new StringBuilder(1000);
        buff.append("[");
        for (Iterator<?> it = elements.iterator(); it.hasNext();) {
            var el = it.next();
            if (el instanceof String) {
                buff.append("\"" + el + "\"");
            } else if (el instanceof List) {
                buff.append(list2String((List<?>) el, cycle++));
            } else {
                buff.append(el.toString());
            }

            if (it.hasNext()) {
                buff.append(instance.feathers[cycle]);
            }
        }
        buff.append("]");

        return buff.toString();
    }

    public static String toJSONString(Class<?> clazz, Object obj, String... feathers) {
        Function<Object, String> toJsonFunc = instances(feathers).toJsonMappings.get(clazz);
        if (obj == null) {
            return "null";
        } else if (clazz == null || toJsonFunc == null) {
            return obj.toString();
        } else {
            return toJsonFunc.apply(obj);
        }
    }
}